{$APPTYPE CONSOLE}
{$RANGECHECKS OFF}

program client_to_erlang;

uses
  SysUtils,
  funcs,
  WinSock,
  EiDelphi,
  ErlDelphi;

const
  hostname   = 'aiming2k';
  cookie     = '123-456';
  connect_as = 'c19';
  connect_to = 'hi';

procedure alert_error(err: String=''; errcode: Integer=0);
begin
(* check erl_errno of:
          EMSGSIZE Buffer too small.
          ENOMEM   No more memory available.
          EIO      I/O error.
*)
  writeln(format('>>> Error(%d): %s', [erl_errno, 'in erl_receive_msg()...']));
  readln;
  halt(0);
end;

var
  fd : Integer;

  buf : AnsiString;
  msg : ErlMessage;
  pmsg: ErlMessage_p;

  got : Integer;
  fromp,tuplep,fnp,argp,resp : PETERM;

  func_name: String;
  func_value: Integer;

  r : Integer;

begin
  // step 1: start erl.exe with params
  //  C:> werl -sname hi -setcookie 123-456

  // step 2: init erlang in delphi
  erl_init;

  // step 3: connect init
  r := erl_connect_init(19, cookie, 0);  // c19@<hostname>
  if r = ERL_ERROR then
    writeln(format('>>> Error(%d): %s', [erl_errno, 'connect init...']))
  else
    writeln('Init success...');

  writeln('node: ', erl_thisnodename, erl_thishostname:20, erl_thisalivename:20, erl_thiscreation:10);

  // step 4: connect as client or server
  fd := erl_connect(connect_to+ '@' + hostname);
  if fd >= 0 then
    writeln('Connect success...')
  else
  begin
    writeln(format('>>> Error(%d): %s', [erl_errno, 'connect...']));
  end;

  // step 5: get and sent messages;
  writeln('Receive messages from other node...');
  SetLength(buf, 1024);
  fillchar(msg, sizeof(msg), 0);
  pmsg := @msg;
  while True do
  try
    got := erl_receive_msg(fd, PAnsiChar(buf), Length(buf), pmsg);
    case got of
      ERL_TICK : begin writeln('tick...'); continue; end;
      ERL_ERROR: alert_error;
    else    // ERL MSG with a Emsg struct
      case msg.type_ of
        EiDelphi.ERL_REG_SEND:
        begin
          writeln('got messages!');

          // get call info.
          fromp := erl_element(2, msg.msg);    // { from, {fn, args}}
          tuplep := erl_element(3, msg.msg);
          fnp := erl_element(1, tuplep);       // fn
          argp := erl_element(2, tuplep);      // args

          // analies
          func_name := String(fnp.aval.a);
          func_value := 0;
          if func_name = 'foo' then
          begin
            func_value := foo(argp.ival.i);
          end
          else if func_name = 'bar' then
          begin
            func_value := bar(argp.ival.i);
          end;
          // more ..

          // return result
          resp := erl_format('{c19, ~i, ~s}', [func_value, 'hello']);
          erl_send(fd, fromp, resp);
          writeln('Send ...');

          // clear
          erl_free_term(msg.from);
          erl_free_term(msg.msg);
          erl_free_term(fromp);
          erl_free_term(tuplep);
          erl_free_term(fnp);
          erl_free_term(argp);
          erl_free_term(resp);
        end;
      else // ERL_SEND, ERL_LINK, ERL_UNLINK and ERL_EXIT
        writeln('unknow msg type:', msg.type_ );
      end;
    end;
  except
    on e:exception do
      writeln('>>> Error: ', e.Message);
  end;

readln;
end.
